package cn.itcast.hotel.service.impl;

import cn.itcast.hotel.mapper.HotelMapper;
import cn.itcast.hotel.pojo.Hotel;
import cn.itcast.hotel.pojo.HotelDoc;
import cn.itcast.hotel.pojo.PageResult;
import cn.itcast.hotel.pojo.RequstParam;
import cn.itcast.hotel.service.IHotelService;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.geo.GeoPoint;
import org.elasticsearch.common.unit.DistanceUnit;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.Operator;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

@Service
public class HotelService extends ServiceImpl<HotelMapper, Hotel> implements IHotelService {

    @Autowired
    private RestHighLevelClient client;

    /**
     * 从Es 进行关键词查询
     * @param requstParam
     * @return
     */
    @Override
    public PageResult search(RequstParam requstParam) {

        String key = requstParam.getKey();
//      创建搜索条件封装对象
        SearchRequest searchRequest = new SearchRequest("hotel");


//        构造bool查询对象
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();

//        如果没传关键词，就是用match all
        if(StringUtils.isBlank(key)){
            boolQuery.must(QueryBuilders.matchAllQuery());
        }else {
//        如果传了关键词
            boolQuery.must(QueryBuilders.matchQuery("all", key).operator(Operator.AND));
        }
        if(StringUtils.isNotBlank(requstParam.getCity())) {
            boolQuery.filter(QueryBuilders.termQuery("city",requstParam.getCity()));
        }
        if(StringUtils.isNotBlank(requstParam.getStarName())) {
            boolQuery.filter(QueryBuilders.termQuery("starName",requstParam.getStarName()));
        }
        if(StringUtils.isNotBlank(requstParam.getBrand())) {
            boolQuery.filter(QueryBuilders.termQuery("brand",requstParam.getBrand()));
        }
        if(requstParam.getMinPrice() !=null && requstParam.getMaxPrice() != null) {
            boolQuery.filter(QueryBuilders.rangeQuery("price")
                    .gte(requstParam.getMinPrice())
                    .lte(requstParam.getMaxPrice()));
        }

        FunctionScoreQueryBuilder functionScoreQuery = QueryBuilders.functionScoreQuery(
                boolQuery,
                new FunctionScoreQueryBuilder.FilterFunctionBuilder[]{
                        new FunctionScoreQueryBuilder.FilterFunctionBuilder(
                                QueryBuilders.termQuery("isAD", true),
                                ScoreFunctionBuilders.weightFactorFunction(10)
                        )
                }
        );

        searchRequest.source().query(functionScoreQuery);

        int index = (requstParam.getPage() -1) * requstParam.getSize();

//        分页
        searchRequest.source().from(index);
        searchRequest.source().size(requstParam.getSize());
//        排序
        if(StringUtils.isNotBlank(requstParam.getLocation())){
            searchRequest.source().sort(SortBuilders.geoDistanceSort(
                    "location",new GeoPoint(requstParam.getLocation()))
                    .order(SortOrder.ASC)
                    .unit(DistanceUnit.KILOMETERS));
        }
        if(StringUtils.isNotBlank(requstParam.getSortBy()) && !"default".equals(requstParam.getSortBy())){
            searchRequest.source().sort(requstParam.getSortBy(), SortOrder.DESC);
        }
        List<HotelDoc> list = new ArrayList<>();
//        发送请求
        try {
            SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
            SearchHit[] hits = response.getHits().getHits();
            for (SearchHit hit : hits) {
                String jsonStr = hit.getSourceAsString();


//                对象转换
                HotelDoc hotelDoc = JSON.parseObject(jsonStr, HotelDoc.class);
//                处理排序结果，距离
                Object[] sortValues = hit.getSortValues();
                if(sortValues.length> 0  && StringUtils.isNotBlank(requstParam.getLocation())){
                    hotelDoc.setDistance(sortValues[0]);
                }
                list.add(hotelDoc);
            }
            PageResult pageResult = new PageResult(response.getHits().getTotalHits().value,
                    list);
            return pageResult;
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("搜索失败");
        }



    }
}
